import axios, { AxiosError, AxiosHeaders, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import { message } from 'antd/lib';
import showCodeMessage from '@/api/code';
import { formatJsonToUrlParams, instanceObject } from '@/utils/format';
import { WithPathOpts } from '@/api/opts';
import NetConfig from '@/config/net';
import { getToken, removeToken } from '@/utils/storage';
import { store } from '@/store';
import { setLogin } from '@/store/reducer/theme/action';

// 创建实例
const axiosInstance: AxiosInstance = axios.create({
  // 前缀
  baseURL: NetConfig.baseURL,
  // 超时
  timeout: NetConfig.requestTimeout,
  withCredentials: false,
  // 请求头
  headers: {
    'Content-Type': NetConfig.contentType,
    Accept: NetConfig.contentType,
  },
});

type Conf = AxiosRequestConfig & { opts?: Partial<WithPathOpts> };

// 请求拦截器
axiosInstance.interceptors.request.use(
  // @ts-ignore
  (config: AxiosRequestConfig) => {
    if (config.headers instanceof AxiosHeaders) {
      config.headers.Authorization = getToken();
    }
    return config;
  },
  (error: AxiosError) => Promise.reject(error),
);

// 响应拦截器
axiosInstance.interceptors.response.use(
  (response: AxiosResponse) => {
    if (NetConfig.successCode.indexOf(response.data[NetConfig.statusName]) !== -1) {
      if (response.config.method !== 'get') message.success(response.data[NetConfig.messageName]);
      return response;
    }
    message.error(response.data[NetConfig.messageName]).then(() => {});
    if (response.data[NetConfig.statusName] === 401) {
      store.dispatch(setLogin(false));
      removeToken();
      window.location.href = '/login';
    }
    return response;
  },
  (error: AxiosError) => {
    const { response } = error;
    if (response) {
      // @ts-ignore
      message.error(showCodeMessage(response.data[NetConfig.statusName]));
      return Promise.reject(response.data);
    }
    message.warning('网络连接异常,请稍后再试!');
    return Promise.reject(error);
  },
);

export const createAPI = (conf: Conf) => {
  conf = conf || {};
  return axiosInstance({
    url: conf.url,
    method: conf.method,
    ...conf.opts,
  });
};

/** resetApi
 * @description id = 123456
 * @description 如get|delete接口为 /user/getUser/123456
 * @description /user/deleteUser/123456
 * @example 示例
 * export const getUserById = (opts: Opts) => {
 *   return createAPI({
 *     method: 'delete',
 *     url: convertRESTAPI('/user/deleteUser/{userId}', opts),
 *     opts,
 *   });
 * };
 */
export const resetApi = (url: string, opts: WithPathOpts): string => {
  if (!opts || !opts.path) return url;

  const pathKeys = Object.keys(opts.path);

  pathKeys.forEach(key => {
    const r = new RegExp(`(:${key}|{${key}})`, 'g');
    // eslint-disable-next-line no-param-reassign
    url = url.replace(r, opts.path[key]);
  });

  return url;
};

const service = {
  get<T = never>(url: string, data?: object): Promise<T> {
    return axiosInstance.get(url, { params: data });
  },

  post<T = never>(url: string, data?: object): Promise<T> {
    return axiosInstance.post(url, data);
  },

  put<T = never>(url: string, data?: object): Promise<T> {
    return axiosInstance.put(url, data);
  },

  delete<T = never>(url: string, data?: object): Promise<T> {
    return axiosInstance.delete(url, data);
  },

  upload: (url: string, file: FormData | File) =>
    axiosInstance.post(url, file, {
      headers: { 'Content-Type': 'multipart/form-data' },
    }),
  download: (url: string, data: instanceObject) => {
    window.location.href = `${NetConfig.baseURL}/${url}?${formatJsonToUrlParams(data)}`;
  },
};

export default service;
